﻿namespace HZY.Framework.Repository.EntityFramework.Monitor;

/// <summary>
/// 监控EFCore缓存
/// </summary>
public static class RepositoryEntityFrameworkMonitorCache
{
    private static readonly EntityFrameworkRepositoriesMonitorContext? EfCoreMonitorContext;
    private static readonly List<EntityFrameworkRepositoriesMonitorSqlContext>? EfCoreMonitorSlowSqlContextList;
    private static readonly Queue<EntityFrameworkRepositoriesMonitorSqlContext>? EfCoreMonitorNewestSqlContextList;

    private static readonly object _obj = new object();

    /// <summary>
    /// 最大慢SQL数据缓存数量
    /// </summary>
    public static int MaxSlowSqlCount { get; private set; } = 20;

    /// <summary>
    /// 最大新SQL数据缓存数量
    /// </summary>
    public static int MaxNewestSqlCount { get; private set; } = 20;

    static RepositoryEntityFrameworkMonitorCache()
    {
        EfCoreMonitorContext ??= new EntityFrameworkRepositoriesMonitorContext();
        EfCoreMonitorSlowSqlContextList ??= new List<EntityFrameworkRepositoriesMonitorSqlContext>();
        EfCoreMonitorNewestSqlContextList ??= new Queue<EntityFrameworkRepositoriesMonitorSqlContext>();
    }

    /// <summary>
    /// efCore 监控上下文
    /// </summary>
    public static EntityFrameworkRepositoriesMonitorContext? Context => EfCoreMonitorContext;

    /// <summary>
    /// 慢 sql 监控上下文
    /// </summary>
    public static List<EntityFrameworkRepositoriesMonitorSqlContext>? SlowSqlContext => EfCoreMonitorSlowSqlContextList;

    /// <summary>
    /// 最新 sql 监控上下文
    /// </summary>
    public static Queue<EntityFrameworkRepositoriesMonitorSqlContext>? NewestSqlContext => EfCoreMonitorNewestSqlContextList;

    #region IDbConnectionInterceptor

    /// <summary>
    /// 设置最大慢SQL数据缓存数量
    /// </summary>
    /// <param name="count"></param>
    public static void SetMaxSlowSqlCount(int count)
    {
        MaxSlowSqlCount = count;
    }

    /// <summary>
    /// 设置最大新SQL数据缓存数量
    /// </summary>
    /// <param name="count"></param>
    public static void SetMaxNewestSqlCount(int count)
    {
        MaxNewestSqlCount = count;
    }

    /// <summary>
    /// 设置打开连接数量
    /// </summary>
    public static void OpenDbConnectionCount()
    {
        if (EfCoreMonitorContext == null) return;
        EfCoreMonitorContext.OpenDbConnectionCount++;
    }

    /// <summary>
    /// 设置关闭连接数量
    /// </summary>
    public static void CloseDbConnectionCount()
    {
        if (EfCoreMonitorContext == null) return;
        EfCoreMonitorContext.CloseDbConnectionCount++;
    }

    /// <summary>
    /// 设置连接失败数量
    /// </summary>
    public static void ConnectionFailedCount()
    {
        if (EfCoreMonitorContext == null) return;
        EfCoreMonitorContext.ConnectionFailedCount++;
    }

    #endregion

    #region IDbCommandInterceptor

    /// <summary>
    /// 创建命令数量
    /// </summary>
    public static void CreateCommandCount()
    {
        if (EfCoreMonitorContext == null) return;
        EfCoreMonitorContext.CreateCommandCount++;
    }

    /// <summary>
    /// 执行命令数量
    /// </summary>
    public static void ExecuteCommandCount()
    {
        if (EfCoreMonitorContext == null) return;
        EfCoreMonitorContext.ExecuteCommandCount++;
    }

    /// <summary>
    /// 命令执行失败数量
    /// </summary>
    public static void CommandFailedCount()
    {
        if (EfCoreMonitorContext == null) return;
        EfCoreMonitorContext.ExecuteCommandCount++;
    }

    #endregion

    #region IDbTransactionInterceptor

    /// <summary>
    /// 创建事务 数量
    /// </summary>
    public static void CreateTransactionCount()
    {
        if (EfCoreMonitorContext == null) return;
        EfCoreMonitorContext.CreateTransactionCount++;
    }

    /// <summary>
    /// 提交事务 数量
    /// </summary>
    public static void SubmitTransactionCount()
    {
        if (EfCoreMonitorContext == null) return;
        EfCoreMonitorContext.SubmitTransactionCount++;
    }

    /// <summary>
    /// 回滚事务 数量
    /// </summary>
    public static void RollBackCount()
    {
        if (EfCoreMonitorContext == null) return;
        EfCoreMonitorContext.RollBackCount++;
    }

    /// <summary>
    /// 事务失败 数量
    /// </summary>
    public static void TransactionFailedCount()
    {
        if (EfCoreMonitorContext == null) return;
        EfCoreMonitorContext.TransactionFailedCount++;
    }

    #endregion

    /// <summary>
    /// 设置 sql 信息
    /// </summary>
    /// <param name="dbCommand"></param>
    /// <param name="elapsedMilliseconds"></param>
    public static void SetSqlInfo(DbCommand dbCommand, long elapsedMilliseconds)
    {
        if (EfCoreMonitorSlowSqlContextList is null || EfCoreMonitorNewestSqlContextList is null) return;

        lock (_obj)
        {
            var context = new EntityFrameworkRepositoriesMonitorSqlContext
            {
                Sql = dbCommand.CommandText,
                ElapsedMilliseconds = elapsedMilliseconds
            };

            AddNewestSqlContext(context);

            AddSlowSqlContext(context);
        }
    }

    /// <summary>
    /// 添加慢Sql记录
    /// </summary>
    /// <param name="sqlContext"></param>
    private static void AddSlowSqlContext(EntityFrameworkRepositoriesMonitorSqlContext sqlContext)
    {
        if (EfCoreMonitorSlowSqlContextList is null) return;

        if (EfCoreMonitorSlowSqlContextList.Count >= MaxSlowSqlCount)
        {
            // 超过配置数量，移除最小的一部分 (防止MaxCount改大后再改小)
            var moreCount = EfCoreMonitorSlowSqlContextList.Count - MaxSlowSqlCount;
            if (moreCount > 0)
            {
                var contexts = EfCoreMonitorSlowSqlContextList.OrderBy(w => w.ElapsedMilliseconds).Take(moreCount).ToList();
                foreach (var item in contexts)
                {
                    EfCoreMonitorSlowSqlContextList.Remove(item);
                }
            }

            // 找到设置数量内，执行时间最小的一条，如果执行时间大于最小的一条，则替换
            var minContext = EfCoreMonitorSlowSqlContextList.MinBy(w => w.ElapsedMilliseconds);
            if (sqlContext.ElapsedMilliseconds >= minContext?.ElapsedMilliseconds)
            {
                EfCoreMonitorSlowSqlContextList.Remove(minContext);
                EfCoreMonitorSlowSqlContextList.Add(sqlContext);
            }
        }
        else
        {
            EfCoreMonitorSlowSqlContextList.Add(sqlContext);
        }
    }

    /// <summary>
    /// 添加最新Sql记录
    /// </summary>
    /// <param name="sqlContext"></param>
    private static void AddNewestSqlContext(EntityFrameworkRepositoriesMonitorSqlContext sqlContext)
    {
        if (EfCoreMonitorNewestSqlContextList is null) return;

        // 超过配置数量，移除最早的一部分
        while (EfCoreMonitorNewestSqlContextList.Count >= MaxNewestSqlCount)
        {
            EfCoreMonitorNewestSqlContextList.Dequeue();
        }

        EfCoreMonitorNewestSqlContextList.Enqueue(sqlContext);
    }
}